package physicsNatures;

import java.awt.Point;

import util.math.Angle;
import util.physics.Force;
import util.physics.Velocity;
import com.golden.gamedev.object.Sprite;

/**
 * Abstract class for physics natures of objects. Newtonian and non-Newtonian
 * physics extend this class.
 *
 * @author Nathan Klug
 * @author Anne Weng
 * 
 */
public abstract class AbstractPhysicsNature {
    protected Sprite mySprite;
    private double myMass;
    
    private boolean isOn;

    /**
     * Constructor for an AbstractPhysicsNature. To use any sort of physics, Newtonian or not,
     * requires an object (the sprite) and some sort of physics defining attribute (the mass).
     * @param sprite
     * @param mass
     */
    public AbstractPhysicsNature(Sprite sprite, double mass) {
        mySprite = sprite;
        myMass = mass;
        isOn = true;
    }

    public abstract void applyForce(Force force, long elapsedTime);

    public abstract void collisionOccurred(AbstractPhysicsNature otherObject, Angle angleOfImpact, Point pointOfImpact, double coefficientOfRestitution);

    public abstract void updateWithPhysics(long elapsedTime);
    
    /**
     * Returns the velocity of the sprite object. Vertical speed is negated to account
     * for Java's definition of positive/negative in graphics.
     * @return
     */
    public Velocity getVelocity(){
        return new Velocity(mySprite.getHorizontalSpeed(), -mySprite.getVerticalSpeed());
    }
    
    /**
     * Sets the new velocity for the sprite object. Vertical speed is negated to account
     * for Java's definition of positive/negative in graphics.
     * @param newVelocity
     */
    protected void setVelocity(Velocity newVelocity){
        mySprite.setHorizontalSpeed(newVelocity.getXComponent());
        mySprite.setVerticalSpeed(-newVelocity.getYComponent());
    }

    /**
     * Returns the mass of the object. Effectively the "physical object attribute" necessary
     * for all physical calculations, so custom physics systems that do not use mass still
     * need to set this even though it is called mass.
     * @return
     */
    public double getMass() {
        return myMass;
    }
    
    /**
     * Returns a boolean value representing if physics is on
     * @return
     */
    public boolean isOn(){
        return isOn;
    }
    
    /**
     * Turns physics off
     */
    public void turnOff(){
        isOn = false;
    }
    
    /**
     * Turns physics on
     */
    public void turnOn(){
        isOn = true;
    }
    
    /**
     * Sets the physics on/off based on the input boolean
     * @param newState
     */
    public void setPhysicsOnOff(boolean newState){
        isOn = newState;
    }
    
    /**
     * Turns physics on if it is off and turns physics off if it is on
     */
    public void togglePhysicsOnOff(){
        isOn = !isOn;
    }
}
